import re

from django.conf import settings
from django.urls import URLPattern, URLResolver
from django.utils.module_loading import import_string

exclude_url_list = [
    '/static/',
    '/swagger/',
    '/redoc/'
]
methodList = ['get', 'post', 'put', 'delete', 'patch']
actions_dict = {'get': '查询', 'post': '新增', 'put': '修改', 'delete': '删除', 'patch': '修改'}


def check_url_exclude(url):
    """
    排除一些特定的URL
    :param url: 待检验的URL
    :return:
    """
    # 将要定向排除的URL(可包含正则) 按照列表的形式写入配置文件 settings.AUTO_DISCOVER_EXCLUDE  下
    for regex in exclude_url_list:
        if re.match(regex, url):
            return True


def get_url_method(item, url_ordered_dict, name, url):
    # try:
    #     print(item.name, item.callback.actions, item.callback.cls, item.callback.initkwargs)
    # except:
    #     try:
    #         print(item.name, item.callback.view_class, item.callback.cls, item.callback.initkwargs)
    #         print(dir(item.callback.cls))
    #     except:
    #         print(item.name)
    url = url.replace('(?P<pk>[0-9]+)', '{id}')
    try:
        actions = getattr(item.callback, 'actions')
        for k in actions.keys():
            url_ordered_dict.append({"name": actions_dict[k], "url": url, 'method': k, 'value': name})
    except:
        # print(type(item.callback.cls), type(item.callback.view_class), dir(item.callback.cls))
        try:
            for k in methodList:
                if k in dir(item.callback.cls):
                    url_ordered_dict.append({"name": actions_dict[k], "url": url, 'method': k, 'value': name})
        except:
            print(name, url)


def recursion_urls(pre_namespace, pre_url, urlpatterns, url_ordered_dict):
    """
    递归的去获取URL
    :param pre_namespace: namespace前缀，用于拼接name
    :param pre_url: url前缀，用于拼接url
    :param urlpatterns: 路由关系列表
    :param url_ordered_dict: 用于保存递归中获取的所有路由
    :return:
    """
    for item in urlpatterns:
        # 已经是根网址，获取name及url写入url_ordered_dict
        if isinstance(item, URLPattern):
            # 没有别名(name)的路由地址直接跳过
            if not item.name:
                continue
            # 拼接路由别名(包含分发下来的namespace；如 "rbac:menu_list")
            if pre_namespace:
                name = "%s:%s" % (pre_namespace, item.name)
            else:
                name = item.name
            # 拼接路由地址URl(包含分发下来的上层路由；如 "/rbac/menu/list")
            # 此时拼接的路由包含起止符号，如：/^rbac/^menu/list/$
            url = pre_url + item.pattern.regex.pattern
            # 删除起止符：/rbac/menu/list/
            url = url.replace("^", "").replace("$", "")
            # 排除一些特定的路由URL
            # 调用check_url_exclude函数定向排除部分URL
            if check_url_exclude(url):
                continue

            get_url_method(item, url_ordered_dict, name, url)

            # url_ordered_dict[name] = {"name": name, "url": url}
        # 路由分发，递归操作
        elif isinstance(item, URLResolver):
            # 上次循环(上一层)分发是否包含namespace
            if pre_namespace:
                # 本次循环(当前层)是否包含namespace
                if item.namespace:
                    # 上层、当前层都包含直接拼接两层的namespace
                    namespace = "%s:%s" % (pre_namespace, item.namespace,)
                else:
                    # 当前层分发不包含namespace，直接用上一层的
                    namespace = pre_namespace
            else:
                if item.namespace:
                    # 上一层分发不包含namespace，直接使用当前层的
                    namespace = item.namespace
                else:
                    # 上一层、当前层都没有，直接定义层none
                    namespace = None
            # 递归继续执行
            recursion_urls(namespace, pre_url + item.pattern.regex.pattern, item.url_patterns, url_ordered_dict)


def get_url_method_list():
    url_list = list()
    md = import_string(settings.ROOT_URLCONF)
    recursion_urls(None, '/', md.urlpatterns, url_list)
    return url_list



